/**
 * @method 获取对象类型
 * @desc - 对object中的null、regexp、array作正确地返回
 * @param {any} obj
 */
export const getRealType = obj => Object.prototype.toString.call(obj).replace(/(^\[object )|(\]$)/g, '').toLowerCase();

/**
 * @method 扁平化对象中的数组属性
 * @param {object or array} result 
 * @desc 原创
 */
export const formatJson = result => {
	let message = void 0;

	try { result = JSON.parse(JSON.stringify(result)); }
	catch(err) { throw new Error(err); }

  if(Array.isArray(result)) {// array
		if(result.length === 1) {
			if(getRealType(result[0]) !== 'object' && !Array.isArray(result[0])) {// 非plain-object，非array
				message = result[0];
			} else {
				message = formatJson(result[0]);
			}
		} else {
			message = [];
			for(const val of result) {
				message.push(formatJson(val));
			}
		}
  } else if(getRealType(result) === 'object') {// plain-object
		message = {};
    for(const key in result) {// 遍历键
			if(getRealType(result[key]) !== 'object'
				&& !Array.isArray(result[key])) {// 其它类型
				message[key] = result[key];
			} else {
				message[key] = formatJson(result[key]);
			}
		}
  } else {// 其它类型直接返回
		message = result;
	}
  return message;
}

/**
 * @method 执行队列任务
 * @param {array} arr 队列任务数组
 */
export const queueByReduce = arr => arr.reduce((promises, item) => promises = promises.then(item), Promise.resolve());

/**
 * @method 获取参数url中的参数
 */
export const getUrlParamsHash = name => {
	if(!window) {
		return '';
	}
	return window.location.href.replace(/^((https|http|ftp|rtsp|mms)?:\/\/)[^\s]+\?{1}/, '')
	.split('&').map((item, index) => {
		const keyval = item.split('=');
		return { key: keyval[0], value: decodeURIComponent(keyval[1]) }
	});
}

/**
 * @method 节流函数
 * 
 * @param {Function} fun 需要节流的函数
 * @param {Number} delay 事件延迟执行时间，默认300ms
 * @param {Number} interval 事件执行间隔时间，默认300ms
 * @returns {Function}
 * 
 * @desc 目的：降低事件执行的频率
 * # 使用闭包 保持 记录 timer计时器 和 last上一次调用时间
 * # interval
 * 调用间隔时间 >= interval间隔时间 则执行一次
 * # delay
 * 调用间隔时间 < interval间隔时间 走以下规则
 * ## 调用间隔时间 < delay
 * 1. 只保留最后一次的延迟执行，因为都被清除了
 * ## 调用间隔时间 > delay
 * 1. 形成大于delay间隔时间的频率执行
 * 2. 这个delay频率一定比intervak的高，即大于delay的时间比interval小
 * # 总结
 * 1. delay和interval之间没什么关系
 * 2. 调用间隔时间和delay、interval才有关系
 * 3. delay小，可能会形成delay间隔时间的执行
 * 4. delay大，其实就是最后一次的执行延迟时间
 */
export const throttle = (fun, delay = 300, interval = 300) => {
	let timer = 0;
	let last = 0;

	return () => {
		const now = +new Date();
		if(!last) last = now;
		if(now - last >= interval) {
			fun();
			last = now;
		} else {
			clearTimeout(timer);
			timer = setTimeout(() => fun(), delay);
		}
	}
}

/**
 * @method 去抖函数
 * 
 * @param {Function} fun 需要去抖的函数
 * @param {Number} delay 延迟触发事件
 * 
 * @desc 只执行最后一次
 * # 利用闭包 保持 记录 timer定时器
 * # delay
 * 1. 调用间隔时间 小于 delay的，都不会被执行
 * 2. 调用间隔时间 大于 delay的， 形成大于delay频率执行
 * 2. 停止调用时，再延迟执行一次
 * # 相当于节流函数中的delay的作用
 */
export const debounce = (fun, delay = 300) => {
	let timer = null;
	return () => {
		clearTimeout(timer);
		timer = setTimeout(() => fun(), delay);
	}
}

/**
 * @method rem布局
 * @param {number} width 设计图宽度，默认640px
 * @desc
 * - 若添加到window.onresize，建议结合去抖函数使用
 * - 要添加meta viewport
 */
export const setRemLayout = (designWidth = 640, maxWidth = 540) => {
	const html = document.documentElement;
	let windowWidth = html.clientWidth;
	windowWidth = Math.min(windowWidth, designWidth);
	html.style.fontSize = Math.min(windowWidth, designWidth) / (designWidth / 100) + 'px';
	document.documentElement.style.fontSize = document.documentElement.clientWidth * 100 / designWidth + 'px';
}

/**
 * @method 获取设备类型
 * @desc 目前支持['Android', 'iPhone', 'iPad', 'Chrome']
 */
export const deviceName = () => {
	const type = ['Android', 'iPhone', 'iPad', 'Chrome'];
	const userAgent = window.navigator.userAgent;
	for(const val of type) {
		if(userAgent.indexOf(val) > -1) return val;
	}
}

/**
 * @method 判断是否移动设备
 */
export const isMobile = () => {
	const userAgent = window.navigator.userAgent;
	if(userAgent.indexOf('Mobile') > -1) {
		return true;
	} else {
		return false;
	}
}

/**
 * @method 响应类型为excel的，转为可下载url
 * @param {*} data 
 * @param {boolean} isDownload
 */
export const excelDataToDownloadUrl = (data, isDownload = false) => {
	const blob = new Blob([data], { type: 'application/vnd.ms-excel' });
	return URL.createObjectURL(blob);
}

/**
 * @method 下载一个可在下载的url
 * @param {可下载的地址} url 
 */
export const downloadByUrl = url => {
	const el = document.createElement('A');
	el.setAttribute('download', url);
	el.setAttribute('href', '');
	el.click();
}